<!-- 学习来源：https://www.bilibili.com/video/BV1LN4y1D7aC/?spm_id_from=333.788.videopod.sections&vd_source=7152d744ecc75d82a35a3ceffd3c94ce -->

<template>
  <div class="text-fault-container">
    <div ref="faultTextsRef" class="fault-text-box" @click="clickFaultText">
      <!-- 故障文字 -->
      <div class="fault-text">CONTEXT</div>
      <div class="fault-text">CONTEXT</div>
      <div class="fault-text">CONTEXT</div>
      <div class="fault-text">CONTEXT</div>
      <div class="fault-text">CONTEXT</div>
    </div>
  </div>
</template>

<!-- 安装vite-plugin-vue-setup-extend插件让<script setup>标签</script>可以直接自定义组件名 -->
<script setup lang="ts" name="TextFault">
const texts: any = []
const faultTextsRef = ref()
let playerInterval: NodeJS.Timeout

const getTextElements = () => {
  texts.push(...faultTextsRef.value.children)
}

// 点击文本开启故障动画
const clickFaultText = () => {
  clearInterval(playerInterval)
  // 到规定时间后清除播放效果定时器，并将样式还原到初始状态
  setTimeout(() => {
    clearInterval(playerInterval)
    texts.forEach((textElement: any) => {
      textElement.classList.remove("faulttext_fault")
      textElement.style.transform = ""
      textElement.style.clipPath = ""
    })
  }, 1 * 1000)
  // 文字故障效果分为三个部分：颜色分离、图像抖动、错位图块
  playerInterval = setInterval(() => {
    texts.forEach((textElement: any) => {
      // 添加 颜色分离 效果
      textElement.classList.add("faulttext_fault")
      // 添加 图像抖动 效果
      textElement.style.transform = `translate(${Math.random() * 60 - 30}%,${Math.random() * 60 - 30}%)`
      // 添加 错位图块 效果
      const x = Math.random() * 100
      const y = Math.random() * 100
      const w = Math.random() * 40 + 10
      const h = Math.random() * 50 + 50
      /**
       * 使用css样式 clip-path 来裁剪可视区（在图层上划定一个可视区域，只有在这个区域里的图层才可以被看到）
       * clip-path的属性：
       * invset()：画一个正方形的可视区
       * circle()：画一个圆形的可视区
       * ellipse()：画一个椭圆形的可视区
       * polygon(x1,y1,x2,y2,x3,y3,x4,y4,......)：画一个多边形的可视区
       * Path()：通过自定义路径画一个任意形状的可视区
       */
      textElement.style.clipPath = `polygon(${x}% ${y}%, ${x + w}% ${y}%, ${x + w}% ${y + h}%, ${x}% ${y + h}%)`
    })
  }, 30)
}

onMounted(() => {
  getTextElements()
})
</script>

<style lang="scss" scoped>
.text-fault-container {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #000000;
  overflow: hidden;
  .fault-text-box {
    position: absolute;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    .fault-text {
      position: absolute;
      font-family: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif;
      color: #ffffff;
      font-size: 5rem;
      letter-spacing: 0.5rem;
      user-select: none;
    }
    .faulttext_fault::before,
    .faulttext_fault::after {
      content: "CONTEXT";
      position: absolute;
      left: 0;
      top: 0;
      mix-blend-mode: screen; // 图形混合模式设置为屏幕混合模式
    }
    .faulttext_fault::before {
      color: #0000ff;
      transform: translateX(-2%);
    }
    .faulttext_fault::after {
      color: #ff0000;
      transform: translateX(2%);
    }
  }
}
</style>
